
class MyPromise {
  constructor (fn) {
    // 设定两种结果回调队列
    this.resolveQueue = []
    this.rejectQueue = []
    this.message = null // 用于传递状态改变时的消息，状态只会改变一次，所以共用此变量
    // 设定初始状态
    this._status = 'PENDING'
    if (typeof (fn) !== 'function') { throw Error('MyPromise 必须传递一个解析函数') }
    // 启动解析
    try {
      // 给用户的启动函数传入状态改变的方法
      fn(this._resolve.bind(this), this._reject.bind(this))
    } catch (err) {
      this._reject(err)
    }
  }
  // 改变 为成功状态
  _resolve (data) {
    if (this._status !== 'PENDING') return this // 状态只能够由 PENDING 出发
    this.message = data
    this._status = 'RESOLVED'
    // 执行成功队列中的方法
    // 设定回调函数，并触发统一执行。
    setTimeout(() => {
      this.resolveQueue.forEach(cb => {
        this._callback = cb || function () {}
        // // 设定回调函数，并触发统一执行。
        this._callback(this.message)
      })
    }, 0)
    return this
  }

  // 改变 为失败状态
  _reject (err) {
    if (this._status !== 'PENDING') return this // 状态只能够由 PENDING 出发
    this.message = err
    this._status = 'REJECTED'
    // 执行失败队列中的方法
    this.rejectQueue.forEach(cb => {
      this._callback = cb || function () {}
      // this._excute(cb)
      setTimeout(() => {
        this._callback(this.message)
      }, 0)
    })
    return this
  }
  // 对外开放的then方法
  then (resolveFunc, rejectFunc) {
    let status = this._status
    this._callback = resolveFunc || function () {}
    // 若状态已经决定，则直接执行用户设定的回调函数
    if (status === 'RESOLVED') {
      // this._excute(resolveFunc)
      setTimeout(_ => {
        this._callback(this.message)
      }, 0)
    }
    if (status === 'REJECTED') {
      this._excute(rejectFunc)
    }
    // 若状态悬而未决，则先推入缓存队列，等待后续执行
    if (status === 'PENDING') {
      this.resolveQueue.push(resolveFunc)
      this.rejectQueue.push(rejectFunc)
    }
    return this
  }
}

// 其他常用 Api
MyPromise.resolve = data => {
  let pro = new MyPromise(function () { })
  pro._resolve(data)
  return pro
}
MyPromise.reject = err => {
  let pro = new MyPromise(function () { })
  pro._reject(err)
  return pro
}
//  测试
let pro = new MyPromise(function (resolve, reject) {
  // setTimeout(function () {
  resolve('asd')
  resolve('asd2')
  // }, 99)
})

pro.then(function (data) {
  console.log(data)
}).then(function (data) {
  console.log(data)
})

console.log(123)
